home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / share / pygtk / 2.0 / codegen / h2def.py < prev    next >
Text File  |  2006-01-20  |  17KB  |  513 lines

  1. #!/usr/bin/env python
  2. # -*- Mode: Python; py-indent-offset: 4 -*-
  3. # Search through a header file looking for function prototypes.
  4. # For each prototype, generate a scheme style definition.
  5. # GPL'ed
  6. # Toby D. Reeves <toby@max.rl.plh.af.mil>
  7.  
  8. # Modified by James Henstridge <james@daa.com.au> to output stuff in
  9. # Havoc's new defs format.  Info on this format can be seen at:
  10. #   http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml
  11.  
  12.  
  13. import string, sys, re, types
  14.  
  15. # ------------------ Create typecodes from typenames ---------
  16.  
  17. _upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])')
  18. _upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])')
  19. _upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])')
  20.  
  21. def to_upper_str(name):
  22.     """Converts a typename to the equivalent upercase and underscores
  23.     name.  This is used to form the type conversion macros and enum/flag
  24.     name variables"""
  25.     name = _upperstr_pat1.sub(r'\1_\2', name)
  26.     name = _upperstr_pat2.sub(r'\1_\2', name)
  27.     name = _upperstr_pat3.sub(r'\1_\2', name, count=1)
  28.     return string.upper(name)
  29.  
  30. def typecode(typename):
  31.     """create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
  32.     return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
  33.  
  34.  
  35. # ------------------ Find object definitions -----------------
  36.  
  37. def strip_comments(buf):
  38.     parts = []
  39.     lastpos = 0
  40.     while 1:
  41.         pos = string.find(buf, '/*', lastpos)
  42.         if pos >= 0:
  43.             parts.append(buf[lastpos:pos])
  44.             pos = string.find(buf, '*/', pos)
  45.             if pos >= 0:
  46.                 lastpos = pos + 2
  47.             else:
  48.                 break
  49.         else:
  50.             parts.append(buf[lastpos:])
  51.             break
  52.     return string.join(parts, '')
  53.  
  54. obj_name_pat = "[A-Z][a-z]*[A-Z][A-Za-z0-9]*"
  55.  
  56. split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)')
  57.  
  58. def find_obj_defs(buf, objdefs=[]):
  59.     """
  60.     Try to find object definitions in header files.
  61.     """
  62.  
  63.     # filter out comments from buffer.
  64.     buf = strip_comments(buf)
  65.  
  66.     maybeobjdefs = []  # contains all possible objects from file
  67.  
  68.     # first find all structures that look like they may represent a GtkObject
  69.     pat = re.compile("struct _(" + obj_name_pat + ")\s*{\s*" +
  70.                      "(" + obj_name_pat + ")\s+", re.MULTILINE)
  71.     pos = 0
  72.     while pos < len(buf):
  73.         m = pat.search(buf, pos)
  74.         if not m: break
  75.         maybeobjdefs.append((m.group(1), m.group(2)))
  76.         pos = m.end()
  77.  
  78.     # handle typedef struct { ... } style struct defs.
  79.     pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" +
  80.                      "(" + obj_name_pat + ")\s+[^}]*}\s*" +
  81.                      "(" + obj_name_pat + ")\s*;", re.MULTILINE)
  82.     pos = 0
  83.     while pos < len(buf):
  84.         m = pat.search(buf, pos)
  85.         if not m: break
  86.         maybeobjdefs.append((m.group(2), m.group(2)))
  87.         pos = m.end()
  88.  
  89.     # now find all structures that look like they might represent a class:
  90.     pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
  91.                      "(" + obj_name_pat + ")Class\s+", re.MULTILINE)
  92.     pos = 0
  93.     while pos < len(buf):
  94.         m = pat.search(buf, pos)
  95.         if not m: break
  96.         t = (m.group(1), m.group(2))
  97.         # if we find an object structure together with a corresponding
  98.         # class structure, then we have probably found a GtkObject subclass.
  99.         if t in maybeobjdefs:
  100.             objdefs.append(t)
  101.         pos = m.end()
  102.  
  103.     pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" +
  104.                      "(" + obj_name_pat + ")Class\s+[^}]*}\s*" +
  105.                      "(" + obj_name_pat + ")Class\s*;", re.MULTILINE)
  106.     pos = 0
  107.     while pos < len(buf):
  108.         m = pat.search(buf, pos)
  109.         if not m: break
  110.         t = (m.group(2), m.group(1))
  111.         # if we find an object structure together with a corresponding
  112.         # class structure, then we have probably found a GtkObject subclass.
  113.         if t in maybeobjdefs:
  114.             objdefs.append(t)
  115.         pos = m.end()
  116.  
  117.     # now find all structures that look like they might represent a class inherited from GTypeInterface:
  118.     pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
  119.                      "GTypeInterface\s+", re.MULTILINE)
  120.     pos = 0
  121.     while pos < len(buf):
  122.         m = pat.search(buf, pos)
  123.         if not m: break
  124.         t = (m.group(1), '')
  125.         t2 = (m.group(1)+'Class', 'GTypeInterface')
  126.         # if we find an object structure together with a corresponding
  127.         # class structure, then we have probably found a GtkObject subclass.
  128.         if t2 in maybeobjdefs:
  129.             objdefs.append(t)
  130.         pos = m.end()
  131.  
  132.     # now find all structures that look like they might represent an Iface inherited from GTypeInterface:
  133.     pat = re.compile("struct _(" + obj_name_pat + ")Iface\s*{\s*" +
  134.                      "GTypeInterface\s+", re.MULTILINE)
  135.     pos = 0
  136.     while pos < len(buf):
  137.         m = pat.search(buf, pos)
  138.         if not m: break
  139.         t = (m.group(1), '')
  140.         t2 = (m.group(1)+'Iface', 'GTypeInterface')
  141.         # if we find an object structure together with a corresponding
  142.         # class structure, then we have probably found a GtkObject subclass.
  143.         if t2 in maybeobjdefs:
  144.             objdefs.append(t)
  145.         pos = m.end()
  146.  
  147. def sort_obj_defs(objdefs):
  148.     objdefs.sort()  # not strictly needed, but looks nice
  149.     pos = 0
  150.     while pos < len(objdefs):
  151.         klass,parent = objdefs[pos]
  152.         for i in range(pos+1, len(objdefs)):
  153.             # parent below subclass ... reorder
  154.             if objdefs[i][0] == parent:
  155.                 objdefs.insert(i+1, objdefs[pos])
  156.                 del objdefs[pos]
  157.                 break
  158.         else:
  159.             pos = pos + 1
  160.     return objdefs
  161.  
  162. def write_obj_defs(objdefs, output):
  163.     if type(output)==types.StringType:
  164.         fp=open(output,'w')
  165.     elif type(output)==types.FileType:
  166.         fp=output
  167.     else:
  168.         fp=sys.stdout
  169.  
  170.     fp.write(';; -*- scheme -*-\n')
  171.     fp.write('; object definitions ...\n')
  172.  
  173.     for klass, parent in objdefs:
  174.         m = split_prefix_pat.match(klass)
  175.         cmodule = None
  176.         cname = klass
  177.         if m:
  178.             cmodule = m.group(1)
  179.             cname = m.group(2)
  180.         fp.write('(define-object ' + cname + '\n')
  181.         if cmodule:
  182.             fp.write('  (in-module "' + cmodule + '")\n')
  183.         if parent:
  184.             fp.write('  (parent "' + parent + '")\n')
  185.         fp.write('  (c-name "' + klass + '")\n')
  186.         fp.write('  (gtype-id "' + typecode(klass) + '")\n')
  187.         # should do something about accessible fields
  188.         fp.write(')\n\n')
  189.  
  190. # ------------------ Find enum definitions -----------------
  191.  
  192. def find_enum_defs(buf, enums=[]):
  193.     # strip comments
  194.     # bulk comments
  195.     buf = strip_comments(buf)
  196.  
  197.     buf = re.sub('\n', ' ', buf)
  198.     
  199.     enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
  200.     splitter = re.compile(r'\s*,\s', re.MULTILINE)
  201.     pos = 0
  202.     while pos < len(buf):
  203.         m = enum_pat.search(buf, pos)
  204.         if not m: break
  205.  
  206.         name = m.group(2)
  207.         vals = m.group(1)
  208.         isflags = string.find(vals, '<<') >= 0
  209.         entries = []
  210.         for val in splitter.split(vals):
  211.             if not string.strip(val): continue
  212.             entries.append(string.split(val)[0])
  213.         if name != 'GdkCursorType':
  214.             enums.append((name, isflags, entries))
  215.         
  216.         pos = m.end()
  217.  
  218. def write_enum_defs(enums, output=None):
  219.     if type(output)==types.StringType:
  220.         fp=open(output,'w')
  221.     elif type(output)==types.FileType:
  222.         fp=output
  223.     else:
  224.         fp=sys.stdout
  225.  
  226.     fp.write(';; Enumerations and flags ...\n\n')
  227.     trans = string.maketrans(string.uppercase + '_', string.lowercase + '-')
  228.     for cname, isflags, entries in enums:
  229.         name = cname
  230.         module = None
  231.         m = split_prefix_pat.match(cname)
  232.         if m:
  233.             module = m.group(1)
  234.             name = m.group(2)
  235.         if isflags:
  236.             fp.write('(define-flags ' + name + '\n')
  237.         else:
  238.             fp.write('(define-enum ' + name + '\n')
  239.         if module:
  240.             fp.write('  (in-module "' + module + '")\n')
  241.         fp.write('  (c-name "' + cname + '")\n')
  242.         fp.write('  (gtype-id "' + typecode(cname) + '")\n')
  243.         prefix = entries[0]
  244.         for ent in entries:
  245.             # shorten prefix til we get a match ...
  246.             # and handle GDK_FONT_FONT, GDK_FONT_FONTSET case
  247.             while ent[:len(prefix)] != prefix or len(prefix) >= len(ent):
  248.                 prefix = prefix[:-1]
  249.         prefix_len = len(prefix)
  250.         fp.write('  (values\n')
  251.         for ent in entries:
  252.             fp.write('    \'("%s" "%s")\n' %
  253.                      (string.translate(ent[prefix_len:], trans), ent))
  254.         fp.write('  )\n')
  255.         fp.write(')\n\n')
  256.  
  257. # ------------------ Find function definitions -----------------
  258.  
  259. def clean_func(buf):
  260.     """
  261.     Ideally would make buf have a single prototype on each line.
  262.     Actually just cuts out a good deal of junk, but leaves lines
  263.     where a regex can figure prototypes out.
  264.     """
  265.     # bulk comments
  266.     buf = strip_comments(buf)
  267.  
  268.     # compact continued lines
  269.     pat = re.compile(r"""\\\n""", re.MULTILINE) 
  270.     buf=pat.sub('',buf)
  271.  
  272.     # Preprocess directives
  273.     pat = re.compile(r"""^[#].*?$""", re.MULTILINE) 
  274.     buf=pat.sub('',buf)
  275.  
  276.     #typedefs, stucts, and enums
  277.     pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE) 
  278.     buf=pat.sub('',buf)
  279.  
  280.     #strip DECLS macros
  281.     pat = re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS""", re.MULTILINE) 
  282.     buf=pat.sub('',buf)
  283.  
  284.     #extern "C"
  285.     pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE) 
  286.     buf=pat.sub('',buf)
  287.  
  288.     #multiple whitespace
  289.     pat = re.compile(r"""\s+""", re.MULTILINE) 
  290.     buf=pat.sub(' ',buf)
  291.  
  292.     #clean up line ends
  293.     pat = re.compile(r""";\s*""", re.MULTILINE) 
  294.     buf=pat.sub('\n',buf)
  295.     buf = buf.lstrip()
  296.  
  297.     #associate *, &, and [] with type instead of variable
  298.     #pat=re.compile(r'\s+([*|&]+)\s*(\w+)')
  299.     pat=re.compile(r' \s* ([*|&]+) \s* (\w+)',re.VERBOSE)
  300.     buf=pat.sub(r'\1 \2', buf)
  301.     pat=re.compile(r'\s+ (\w+) \[ \s* \]',re.VERBOSE)
  302.     buf=pat.sub(r'[] \1', buf)
  303.  
  304.     # make return types that are const work.
  305.     buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
  306.     buf = string.replace(buf, 'const ', 'const-')
  307.  
  308.     return buf
  309.  
  310. proto_pat=re.compile(r"""
  311. (?P<ret>(-|\w|\&|\*)+\s*)  # return type
  312. \s+                   # skip whitespace
  313. (?P<func>\w+)\s*[(]   # match the function name until the opening (
  314. \s*(?P<args>.*?)[)]     # group the function arguments
  315. """, re.IGNORECASE|re.VERBOSE)
  316. #"""
  317. arg_split_pat = re.compile("\s*,\s*")
  318.  
  319. def define_func(buf,fp, prefix):
  320.     buf=clean_func(buf)
  321.     buf=string.split(buf,'\n')
  322.     for p in buf:
  323.         if len(p)==0: continue
  324.         m=proto_pat.match(p)
  325.         if m==None:
  326.             if verbose:
  327.                 sys.stderr.write('No match:|%s|\n'%p)
  328.             continue
  329.         func = m.group('func')
  330.         if func[0] == '_':
  331.             continue
  332.         ret = m.group('ret')
  333.         args=m.group('args')
  334.         args=arg_split_pat.split(args)
  335.         for i in range(len(args)):
  336.             spaces = string.count(args[i], ' ')
  337.             if spaces > 1:
  338.                 args[i] = string.replace(args[i], ' ', '-', spaces - 1)
  339.                 
  340.         write_func(fp, func, ret, args, prefix)
  341.  
  342. get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+')
  343. pointer_pat = re.compile('.*\*$')
  344. func_new_pat = re.compile('(\w+)_new$')
  345.  
  346. def write_func(fp, name, ret, args, prefix):
  347.     if len(args) >= 1:
  348.         # methods must have at least one argument
  349.         munged_name = string.replace(name, '_', '')
  350.         m = get_type_pat.match(args[0])
  351.         if m:
  352.             obj = m.group(2)
  353.             if munged_name[:len(obj)] == string.lower(obj):
  354.                 regex = string.join(map(lambda x: x+'_?',string.lower(obj)),'')
  355.                 mname = re.sub(regex, '', name, 1)
  356.                 if prefix:
  357.                     l = len(prefix) + 1
  358.                     if mname[:l] == prefix and mname[l+1] == '_':
  359.                         mname = mname[l+1:]
  360.                 fp.write('(define-method ' + mname + '\n')
  361.                 fp.write('  (of-object "' + obj + '")\n')
  362.                 fp.write('  (c-name "' + name + '")\n')
  363.                 if ret != 'void':
  364.                     fp.write('  (return-type "' + ret + '")\n')
  365.                 else:
  366.                     fp.write('  (return-type "none")\n')
  367.                 is_varargs = 0
  368.                 has_args = len(args) > 1
  369.                 for arg in args[1:]:
  370.                     if arg == '...':
  371.                         is_varargs = 1
  372.                     elif arg in ('void', 'void '):
  373.                         has_args = 0
  374.                 if has_args:
  375.                     fp.write('  (parameters\n')
  376.                     for arg in args[1:]:
  377.                         if arg != '...':
  378.                             tupleArg = tuple(string.split(arg))
  379.                             if len(tupleArg) == 2:
  380.                                 fp.write('    \'("%s" "%s")\n' % tupleArg)
  381.                     fp.write('  )\n')
  382.                 if is_varargs:
  383.                     fp.write('  (varargs #t)\n')
  384.                 fp.write(')\n\n')
  385.                 return
  386.     if prefix:
  387.         l = len(prefix)
  388.         if name[:l] == prefix and name[l] == '_':
  389.             fname = name[l+1:]
  390.         else:
  391.             fname = name
  392.     else:
  393.         fname = name
  394.     # it is either a constructor or normal function
  395.     fp.write('(define-function ' + fname + '\n')
  396.     fp.write('  (c-name "' + name + '")\n')
  397.  
  398.     # Hmmm... Let's asume that a constructor function name
  399.     # ends with '_new' and it returns a pointer.
  400.     m = func_new_pat.match(name)
  401.     if pointer_pat.match(ret) and m:
  402.         cname = ''
  403.     for s in m.group(1).split ('_'):
  404.         cname += s.title()
  405.     if cname != '':
  406.         fp.write('  (is-constructor-of "' + cname + '")\n')
  407.  
  408.     if ret != 'void':
  409.         fp.write('  (return-type "' + ret + '")\n')
  410.     else:
  411.         fp.write('  (return-type "none")\n')
  412.     is_varargs = 0
  413.     has_args = len(args) > 0
  414.     for arg in args:
  415.         if arg == '...':
  416.             is_varargs = 1
  417.         elif arg in ('void', 'void '):
  418.             has_args = 0
  419.     if has_args:
  420.         fp.write('  (parameters\n')
  421.         for arg in args:
  422.             if arg != '...':
  423.                 tupleArg = tuple(string.split(arg))
  424.                 if len(tupleArg) == 2:
  425.                     fp.write('    \'("%s" "%s")\n' % tupleArg)
  426.         fp.write('  )\n')
  427.     if is_varargs:
  428.         fp.write('  (varargs #t)\n')
  429.     fp.write(')\n\n')
  430.  
  431. def write_def(input,output=None, prefix=None):
  432.     fp = open(input)
  433.     buf = fp.read()
  434.     fp.close()
  435.  
  436.     if type(output) == types.StringType:
  437.         fp = open(output,'w')
  438.     elif type(output) == types.FileType:
  439.         fp = output
  440.     else:
  441.         fp = sys.stdout
  442.  
  443.     fp.write('\n;; From %s\n\n' % input)
  444.     buf = define_func(buf, fp, prefix)
  445.     fp.write('\n')
  446.  
  447. # ------------------ Main function -----------------
  448.  
  449. verbose=0
  450. def main(args):
  451.     import getopt
  452.     global verbose
  453.  
  454.     onlyenums = 0
  455.     onlyobjdefs = 0
  456.     separate = 0
  457.     modulename = None
  458.     opts, args = getopt.getopt(args[1:], 'vs:m:',
  459.                                ['onlyenums', 'onlyobjdefs',
  460.                                 'modulename=', 'separate='])
  461.     for o, v in opts:
  462.         if o == '-v':
  463.             verbose = 1
  464.         if o == '--onlyenums':
  465.             onlyenums = 1
  466.         if o == '--onlyobjdefs':
  467.             onlyobjdefs = 1
  468.         if o in ('-s', '--separate'):
  469.             separate = v
  470.         if o in ('-m', '--modulename'):
  471.             modulename = v
  472.             
  473.     if not args[0:1]:
  474.         print 'Must specify at least one input file name'
  475.         return -1
  476.  
  477.     # read all the object definitions in
  478.     objdefs = []
  479.     enums = []
  480.     for filename in args:
  481.         buf = open(filename).read()
  482.         find_obj_defs(buf, objdefs)
  483.         find_enum_defs(buf, enums)
  484.     objdefs = sort_obj_defs(objdefs)
  485.  
  486.     if separate:
  487.         types = file(separate + '-types.defs', 'w')
  488.         methods = file(separate + '.defs', 'w')
  489.         
  490.         write_obj_defs(objdefs,types)
  491.         write_enum_defs(enums,types)
  492.         types.close()
  493.         print "Wrote %s-types.defs" % separate
  494.         
  495.         for filename in args:
  496.             write_def(filename,methods,prefix=modulename)
  497.         methods.close()
  498.         print "Wrote %s.defs" % separate
  499.     else:
  500.         if onlyenums:
  501.             write_enum_defs(enums,None)
  502.         elif onlyobjdefs:
  503.             write_obj_defs(objdefs,None)
  504.         else:
  505.             write_obj_defs(objdefs,None)
  506.             write_enum_defs(enums,None)
  507.  
  508.             for filename in args:
  509.                 write_def(filename,None,prefix=modulename)
  510.             
  511. if __name__ == '__main__':
  512.     sys.exit(main(sys.argv))
  513.